﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;
using JSONDotNET.Syntax;
using JSONDotNET;

namespace DynamicJSONDeserializer
{
    public class DynamicJSONObject : DynamicObject
    {
        public static dynamic Deserialize(string text)
        {
            return Deserialize(Parser.ParseText(text));
        }
        public static dynamic Deserialize(CompilationUnit cu)
        {
            return new DynamicJSONObject(cu.Unit);
        }

        private Dictionary<string, object> storage;

        private DynamicJSONObject(ParsedObject obj)
        {
            storage = new Dictionary<string, object>();

            foreach (var member in obj.Members)
            {
                var propertyName = member.Name;
                storage[propertyName] = getVal(member.Value);
            }
        }

        private dynamic getVal(ParsedValue val)
        {
            var propertyValueType = val.GetType();
            if (propertyValueType == typeof(ParsedObject))
            {
                return new DynamicJSONObject(val as ParsedObject);
            }
            else if (propertyValueType == typeof(ArrayValue))
            {
                dynamic[] elems = new dynamic[(val as ArrayValue).Value.Count];

                for (int i = 0; i < elems.Length; i++)
                {
                    elems[i] = getVal((val as ArrayValue).Value[i]);
                }
                return elems;
            }
            else if (propertyValueType == typeof(IntNumberValue))
            {
                return ((IntNumberValue)val).Value;
            }
            else if (propertyValueType == typeof(DoubleNumberValue))
            {
                return ((DoubleNumberValue)val).Value;
            }
            else if (propertyValueType == typeof(StringValue))
            {
                return ((StringValue)val).Value;
            }
            else if (propertyValueType == typeof(TrueValue))
            {
                return true;
            }
            else if (propertyValueType == typeof(FalseValue))
            {
                return false;
            }
            else if (propertyValueType == typeof(NullValue))
            {
                return null;
            }

            return null;
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            if (!storage.ContainsKey(binder.Name))
                throw new ArgumentException(string.Format("Object does not have property with name '{0}'", binder.Name));

            result = storage[binder.Name];
            return true;
        }
    }
}
